题解 P1967 货车运输

题意:$n$个节点,$m$条边,$q$个询问,对于每个询问求图中两点间所有路径中最小边权的最大值

对于一条边,我们可以走另一条最小边权的最大值;比这条边的权值大的路径,所以对于原图,我们只需求最大生成树,然后求$LCA$即可,在倍增求$LCA$的同时算一个数组$w$表示最小边权的最大值;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <bits/stdc++.h>
#define ll long long
#define sqr(x) ((x)*(x))
struct node1{
int dis,to,next;
}e[300000];
struct node{
int u,v,d;
}ed[300000];
using namespace std;
inline void write(int x) {if (x<0) putchar('-'),x=-x;if (x>=10) write(x/10);putchar(x%10|'0');}
inline void wln(int x) {write(x);puts("");}
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,m,head[300000],fa[300000],dep[300000],f[300000][22],w[300000][22],cnt,vis[300000];
inline void add(int u,int v,int d){
e[++cnt].to=v;
e[cnt].dis=d;
e[cnt].next=head[u];
head[u]=cnt;
}
int find(int k){return fa[k]==k?k:fa[k]=find(fa[k]);}
inline bool cmp(node a,node b){return a.d>b.d;}
void Kruskal(){
sort(ed+1,ed+1+m,cmp);
for (int i=1;i<=n;++i)fa[i]=i;
int cnt=0;
for (int i=1;i<=m;++i){
if (find(ed[i].u)==find(ed[i].v)) continue;
fa[find(ed[i].u)]=find(ed[i].v);
add(ed[i].u,ed[i].v,ed[i].d);
add(ed[i].v,ed[i].u,ed[i].d);
++cnt;
}
}
inline void deal_lca(int u,int fa){
vis[u]=1;
for (int i=1;i<=20;++i)
f[u][i]=f[f[u][i-1]][i-1],w[u][i]=min(w[u][i-1],w[f[u][i-1]][i-1]);
for (int i=head[u];i;i=e[i].next){
int v=e[i].to;
if (vis[v])continue;
dep[v]=dep[u]+1;
f[v][0]=u;w[v][0]=e[i].dis;
deal_lca(v,u);
}
}
inline int lca(int x,int y){
if (find(x)!=find(y))return -1;
int res=2100000000;
if (dep[x]<dep[y])swap(x,y);
for (int i=20;i>=0;--i){
if (dep[f[x][i]]>=dep[y])res=min(res,w[x][i]),x=f[x][i];
}
if (x==y)return res;
for (int i=20;i>=0;--i){
if (f[x][i]!=f[y][i])
res=min(res,min(w[x][i],w[y][i])),x=f[x][i],y=f[y][i];
}
return min(res,min(w[x][0],w[y][0]));
}
int main(){
n=read(),m=read();
for (int i=1;i<=m;++i)
ed[i].u=read(),ed[i].v=read(),ed[i].d=read();
Kruskal();
for (int i=1;i<=n;++i)
if (!vis[i]){
dep[i]=1;
deal_lca(i,0);
f[i][0]=i;
w[i][0]=2100000000;
}
for (int i=1;i<=20;++i)
for (int j=1;j<=n;++j){
f[j][i]=f[f[j][i-1]][i-1];
w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);
}
int q=read();
while(q--){
int x=read(),y=read();
wln(lca(x,y));
}
return 0;
}